package csc420groupproject;

import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.filechooser.FileFilter;

public class CustomActionListener implements ActionListener {

    private static final String PATH = "/icons/symbols/";

    private boolean isDebug = false;
    private GUI gui;
    private FileFilter inFiles = new TexFilter();
    private FileFilter outFiles = new PdfFilter();

    /**
     * 
     * @param gui
     */
    public CustomActionListener(GUI gui) {
        super();

        if (gui == null) {
            throw new NullPointerException("You can't set the GUI to NULL");
        }

        this.gui = gui;
    }

    /**
     * 
     * @param gui
     * @param isDebug
     */
    public CustomActionListener(GUI gui, boolean isDebug) {
        super();

        if (gui == null) {
            throw new NullPointerException("You can't set the GUI to NULL");
        }

        this.isDebug = isDebug;
        this.gui = gui;
    }

    /**
     *
     * @param evt
     */
    public void actionPerformed(ActionEvent evt) {
        String command = evt.getActionCommand();
        File file;

        //menu commands; where applicable, duplicate commands are handled by the 
        //      menu
        //new
        if(command.equals("New")) {
            this.gui.latexCodeArea.setText(GUI.BOILERPLATE);
            this.gui.latexCodeArea.setCaretPosition(this.gui.latexCodeArea.getText()
                    .indexOf("\n") + 1);
        //open file
        }else if(command.equals("Open")) {
            this.gui.fileChooser.removeChoosableFileFilter(this.outFiles);
            this.gui.fileChooser.setFileFilter(this.inFiles);
                if(this.gui.fileChooser.showOpenDialog(this.gui) == JFileChooser.APPROVE_OPTION) {
                    file = this.gui.fileChooser.getSelectedFile();
                    BufferedReader read;

                    try {
                        read = new BufferedReader(new FileReader(file));
                        this.gui.latexCodeArea.setText("");
                        String line;

                        while ((line = read.readLine()) != null)
                            this.gui.latexCodeArea.append(line + "\n");

                        read.close();

                        this.gui.compilerReturnArea.append(file.getName() + " opened.\n");
                    } catch (FileNotFoundException e) {
                        this.gui.compilerReturnArea.append("File not found\n");
                        this.gui.south.setVisible(true);
                        this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                    } catch (IOException e) {
                        this.gui.compilerReturnArea.append("Unable to completely read file.\n");
                        this.gui.south.setVisible(true);
                        this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                    }
                } else
                    this.gui.compilerReturnArea.append("Open canceled.\n");
        //save file
        }else if(command.equals("Save")) {
            this.gui.fileChooser.removeChoosableFileFilter(this.outFiles);
            this.gui.fileChooser.setFileFilter(this.inFiles);
            if(this.gui.fileChooser.showSaveDialog(this.gui) == JFileChooser.APPROVE_OPTION) {
                file = this.gui.fileChooser.getSelectedFile();
                PrintWriter writer;
                try {
                    file.createNewFile();
                    writer = new PrintWriter(file);
		    StringTokenizer tok = new StringTokenizer(this.gui.latexCodeArea.getText());
		    while (tok.hasMoreTokens()) 
			writer.println(tok.nextToken());
                    writer.close();
                    this.gui.compilerReturnArea.append(file.getName() + " saved.\n");
                } catch (FileNotFoundException e) {
                    this.gui.compilerReturnArea.append("Unable to open file for saving.\n");
                    this.gui.south.setVisible(true);
                    this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                } catch (IOException e) {
                    this.gui.compilerReturnArea.append("Unable to save file.\n");
                    this.gui.south.setVisible(true);
                    this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                }
            }else
                this.gui.compilerReturnArea.append("Save aborted.\n");
        //export
        }else if(command.equals("Export")) {
            this.gui.fileChooser.removeChoosableFileFilter(this.inFiles);
            this.gui.fileChooser.setFileFilter(this.outFiles);
            if(this.gui.fileChooser.showSaveDialog(this.gui) == JFileChooser.APPROVE_OPTION) {
                file = this.gui.fileChooser.getSelectedFile();
                PrintWriter writer;
                try {
                    String pathToFile = file.getParent();
                    File temp = new File("temp.tex");
                    temp.createNewFile();
                    writer = new PrintWriter(temp);
		    StringTokenizer tok = new StringTokenizer(this.gui.latexCodeArea.getText());
		    while (tok.hasMoreTokens()) 
			writer.println(tok.nextToken());
                    writer.close();
                    Runtime.getRuntime().exec("pdflatex " + "\"" + temp.getAbsolutePath().
                            substring(0, temp.getAbsolutePath().length() - 4) + "\"");

                    // clean up
                    temp.delete();
                    File clean = new File(pathToFile + File.separator + "temp.pdf");
                    clean.renameTo(file);

                    this.gui.compilerReturnArea.append(file.getName() + " saved.\n");
                } catch (FileNotFoundException e) {
                    this.gui.compilerReturnArea.append("Unable to open file for saving.\n");
                    this.gui.south.setVisible(true);
                    this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                } catch (IOException e) {
                    this.gui.compilerReturnArea.append("Unable to export.\n");
                    this.gui.south.setVisible(true);
                    this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                }
            }else
                this.gui.compilerReturnArea.append("Export aborted.\n");
        //close file
        }else if(command.equals("Close")) {
            this.gui.latexCodeArea.setText("");
        //exit
        }else if(command.equals("Exit")) {
            System.exit(0);
        //about
        }else if(command.equals("About")) {
            JPanel dialogPanel = new JPanel();
            dialogPanel.setLayout(new BoxLayout(dialogPanel, BoxLayout.Y_AXIS));
            JLabel [] labels = new JLabel[5];

            String[] dialogText = { "created by: ",
                                    "            William Goodwin",
                                    "            Karl Miller",
                                    "            Dave Renz"
            };
            labels[0] = new JLabel(new ImageIcon(getClass().getResource("/icons/logo.png")));
            dialogPanel.add(labels[0]);

            for(int i=1; i<labels.length; i++) {
                labels[i] = new JLabel(dialogText[i-1]);
                dialogPanel.add(labels[i]);
            }
            CustomJDialog jDialogBox = CustomJDialog.getInstance(this.gui,
                    "TexEdit 1.1b", true, dialogPanel, CustomJDialog.ONLY_OK);
            jDialogBox.setVisible(true);
        //help
        }else if(command.equals("Help")) {
            //need to redo in JPanels
            String[] dialogText = {" LaTeX Tutorial: ",
                    " http://www.andy-roberts.net/misc/latex/"};
            CustomJDialog jDialogBox = CustomJDialog.getInstance(this.gui,
                    "TeXEdit 1.1b Help", true, dialogText, CustomJDialog.ONLY_OK);
            jDialogBox.setVisible(true);
        //preview
        }else if (command.equals("Preview")) {
            boolean compilerReturnsError = false;

            String text = this.gui.latexCodeArea.getText();

            if(text.length() > 0) {
                PreviewPane preview;
                String[] files;
                File dir = new File("previewtemp");
                dir = dir.getAbsoluteFile();

                PrintWriter writer;
                try {
                    if(!dir.exists())
                        dir.mkdir();
                    File temp = new File("previewtemp" +
                            File.separator + "temp.tex");
                    temp = temp.getAbsoluteFile();
                    File tempDvi = new File("previewtemp" +
                            File.separator + "temp.dvi");
                    tempDvi = tempDvi.getAbsoluteFile();
                    temp.createNewFile();
                    tempDvi.createNewFile();
                    writer = new PrintWriter(temp);
		    StringTokenizer tok = new StringTokenizer(text);
		    while (tok.hasMoreTokens()) 
			writer.println(tok.nextToken());
                    writer.close();

                    Runtime.getRuntime().exec("latex "+ "\"" + temp.getAbsolutePath()
                            .substring(0, temp.getAbsolutePath().length() - 4) + "\"");
                    Runtime.getRuntime().exec("dvipng " + "\"" + tempDvi.getAbsolutePath()
                            .substring(0, tempDvi.getAbsolutePath().length() - 4) + "\"");

                    temp.delete();
                    tempDvi.delete();

                    File images[] = dir.listFiles();

                    files = new String[images.length];

                    for (int i = 0; i < files.length; ++i)
                        files[i] = new String(images[i].getName());

                    preview = new PreviewPane(files);

                    CustomJDialog jDialogBox = CustomJDialog.getInstance(this.gui,
                        "Preview", true, preview, CustomJDialog.ONLY_OK);
                    jDialogBox.setVisible(true);
                    // finish cleanup
                    for (int j = 0; j < images.length; ++j)
                        images[j].delete();

                    dir.delete();
                } catch (FileNotFoundException e) {
                    this.gui.compilerReturnArea.append("Unable to open file.");
                    this.gui.compilerReturnArea.setVisible(true);
                } catch (IOException e) {
                    this.gui.compilerReturnArea.append("Unable to generate preview");
                    this.gui.compilerReturnArea.setVisible(true);
                }
            } else {
                compilerReturnsError = true;
                String[] dialogText = {"LaTeX code Area is empty"};
                CustomJDialog jDialogBox = CustomJDialog.getInstance(this.gui,
                        "No Code!!", true, dialogText, CustomJDialog.ONLY_OK);
                jDialogBox.setVisible(true);
            }
            if(compilerReturnsError){
                this.gui.south.setVisible(true);
                this.gui.showHideCompileAreaButton.setText("Hide Compiler Return Area");
                this.gui.compilerReturnArea.append("Compiler error.\n");
            }
        //options
        } else if (command.equals("Options")){
            gui.optionsFrame.setVisible(true);
        //set foreground/text color
        } else if (command.equals("Set Foreground Color")){
            System.out.println("fore");
            gui.foreground = gui.colorChooserFore.getColor();
            UIManager.put("Panel.foreground", gui.foreground);
            gui.iterateThroughContainer(gui);
            //unfortunately, there isn't a way I've found around statically
            //changing the text area colors
            gui.setTextAreasColor();
            //this needs to be here for JFileChooser
        //set background color
        } else if (command.equals("Set Background Color")){
            System.out.println("back");
            gui.background = gui.colorChooserBack.getColor();
            UIManager.put("Panel.background", gui.background);
            gui.iterateThroughContainer(gui);
            //unfortunately, there isn't a way I've found around statically
            //changing the text area colors
            gui.setTextAreasColor();
            //this needs to be here for JFileChooser
        //symbol
        }else if(command.equals("mathSymbol")) {
            SymbolActionListener symbolListener = new SymbolActionListener(this.gui);
            String [] symbolNames = {
                    "leq", "geq", "neq", "equiv", "propto",
                    "cong", "approx", "times", "divide", "infinity",
                    "implies", "forall", "exists", "empty", "neg",
                    "subset", "subseteq", "supset", "supseteq", "in",
                    "notin", "inter", "union", "integral", "partial"
            };
            String [] toolTips = {
                    "Less than/equal to", "Greater than/equal to", "Not equal to", "Equivalent", "Proportional to",
                    "Congruent", "Approximately", "Times", "Divide", "Infinity",
                    "Implies", "For all", "Exists", "Empty set", "Negates",
                    "Subset", "Subset Equal to", "Super set", "Super set equal to", "In",
                    "Not in", "Intersection", "Union", "Integral", "Partial"
            };

            JButton [] symbolButtons = new JButton[symbolNames.length];
            JPanel buttonPanel = new JPanel(new GridLayout(5, 5));

            for(int i=0; i<symbolNames.length; i++) {
                symbolButtons[i] = new JButton(new ImageIcon(getClass().getResource
                        (PATH + symbolNames[i] +".png")));
                symbolButtons[i].setActionCommand(symbolNames[i]);
                symbolButtons[i].setToolTipText(toolTips[i]);
                symbolButtons[i].addActionListener(symbolListener);
                buttonPanel.add(symbolButtons[i]);
            }

            CustomJDialog jDialogBox = CustomJDialog.getInstance(this.gui,
                    "Symbols", false, buttonPanel, CustomJDialog.ONLY_CLOSE);
            jDialogBox.setVisible(true);
            this.gui.formulaField.requestFocus();

        //math symbols
        }else if(this.gui.symbolMap.get(command) != null) {
            String oldFormula = this.gui.formulaField.getText();

            //if something is selected, remove it when we place in new text
            int start, end;
            if((start = gui.formulaField.getSelectionStart()) !=
                    (end = gui.formulaField.getSelectionEnd())){

                oldFormula = oldFormula.substring(0, start) +
                        oldFormula.substring(end);

                if(isDebug)
                    System.out.println("test: " + oldFormula);

                this.gui.formulaField.setText(oldFormula);
                this.gui.formulaField.setCaretPosition(start);
            }
            this.gui.formulaField.setText(oldFormula.substring(0,
                    this.gui.formulaField.getCaretPosition()) +
                    this.gui.symbolMap.get(command) + oldFormula.substring(
                    this.gui.formulaField.getCaretPosition()));
        /*
         * text mode commands
         * if the user uses one of the text panel buttons, we separate the
         * test in the LaTeX text area, insert the proper text for the command
         * they pressed, and reinsert the cursor where it should be
         */
        }else if(this.gui.functions.get(command) != null) {
            int oldCarotLoc = this.gui.latexCodeArea.getCaretPosition();
            String oldText = this.gui.latexCodeArea.getText();

            this.gui.latexCodeArea.setText(oldText.substring(0, this.gui
                    .latexCodeArea.getCaretPosition()) + this.gui.functions.get(command) + 
                    oldText.substring(this.gui.latexCodeArea.getCaretPosition()));

            Integer temp = ((temp = this.gui.functionsCursorLoc.get(command)) == null)?0:temp;
            //if the value is in the hashmap and its center carot location is
            //listed, then set the cursor to the right spot, otherwise, just
            //set it to where it was before
            this.gui.latexCodeArea.setCaretPosition(oldCarotLoc + temp);
        //buttons
        }else if (evt.getSource() instanceof JButton) {
            //math toolbar button
            if (this.gui.formulas.get(command) != null) {
                String oldFormula = this.gui.formulaField.getText();

                //if something is selected, remove it when we place in new text
                int start, end;
                if((start = gui.formulaField.getSelectionStart()) !=
                        (end = gui.formulaField.getSelectionEnd())){
                    
                    oldFormula = oldFormula.substring(0, start) +
                            oldFormula.substring(end);
                    
                    if(isDebug)
                        System.out.println("test: " + oldFormula);

                    this.gui.formulaField.setText(oldFormula);
                    this.gui.formulaField.setCaretPosition(start);
                }
                this.gui.formulaField.setText(oldFormula.substring(0,
                        this.gui.formulaField.getCaretPosition()) + 
                        this.gui.formulas.get(command) + oldFormula.substring(
                        this.gui.formulaField.getCaretPosition()));
            //switch to math mode
            } else if(command.equals("Math Mode")){
                this.alternateModes(true);
                this.gui.formulaMainPanel.setVisible(true);
                this.gui.toolBarPanel.setSelectedComponent(this.gui.mathToolBar);
            //switch to text mode
            } else if(command.equals("Text Mode")){
                this.alternateModes(false);
                this.gui.formulaMainPanel.setVisible(false);
                this.gui.toolBarPanel.setSelectedComponent(this.gui.textToolBar);
            //hide compiler window
            } else if(command.equals("Hide Compiler Return Area")){
                ((JButton)evt.getSource()).setText("Show Compiler Return Area");
                this.gui.south.setVisible(false);
            //show compiler window
            } else if(command.equals("Show Compiler Return Area")){
                ((JButton)evt.getSource()).setText("Hide Compiler Return Area");
                this.gui.south.setVisible(true);
            //enter
            }else if(command.equals("Enter")) {
                //formula field is empty or null
                if(this.gui.formulaField.getText().length() <= 0) {
                    String dialogText[] = {"Formula area is empty"};
                    CustomJDialog jDialogBox = CustomJDialog.getInstance(this.gui,
                            "No Code!!", true, dialogText, CustomJDialog.ONLY_OK);
                    jDialogBox.setVisible(true);
                //formula field has text in it
                }else {
                    ((GUI)((JButton) evt.getSource()).getTopLevelAncestor())
                        .copyFromFormulaBarToMainArea();
                }
            //clear
            }else if(command.equals("Clear")) {
                this.gui.formulaField.setText("");
            }
        //event came from something else
        }else {
            if(this.isDebug)
                System.out.println("Functionality not Supported: " + command);
        }
        //hack to get the gui to repaint properly
        this.gui.repaint();
        this.gui.setSize(this.gui.getWidth() + 1, this.gui.getHeight() + 1);
        this.gui.setSize(this.gui.getWidth() - 1, this.gui.getHeight() - 1);
    }

    /**
     * 
     * @param gui
     */
    public void setGUI(GUI gui) {
        this.gui = gui;

        if (gui == null) {
            throw new NullPointerException("You can't set the GUI to NULL");
        }
    }

    /**
     * 
     * @return
     */
    public GUI getGUI() {
        return this.gui;
    }

    /**
     * @param isMathModeEnabling
     */
    private void alternateModes(boolean isMathModeEnabling) {
        JMenuBar menuBar = gui.getJMenuBar();

        for (Component n : menuBar.getComponents()) {
            //we check this just in case there is a non JMenu in the JMenuBar
            if (n instanceof JMenu) {
                JMenu castedN = (JMenu) n;

                if (castedN.getText().equals("View")) {

                    for (Component j : castedN.getMenuComponents()) {
                        if (j instanceof JMenuItem) {
                            JMenuItem castedJ = (JMenuItem) j;

                            if (castedJ.getText().equals("Text Mode")) {

                                if (this.isDebug) {
                                    System.out.println(isMathModeEnabling +
                                            " text mode button");
                                }

                                castedJ.setEnabled(isMathModeEnabling);
                            } else if (castedJ.getText().equals("Math Mode")) {

                                if (this.isDebug) {
                                    System.out.println(!isMathModeEnabling +
                                            " math mode button");
                                }

                                castedJ.setEnabled(!isMathModeEnabling);
                            }
                        }
                    }
                    break;
                }
            }
        }
    }
}
